﻿using System;
using System.Xml.Linq;
using AzukiMap.Tools;
using GeoAPI.CoordinateSystems;
using GeoAPI.Geometries;

namespace AzukiMap.MapSource
{
    public abstract class MapSource : IMapSource
    {
        protected CoordinationUnits _coordUnit;
        protected GeometryUtil _geoUtil;
        protected double _maxScale;
        protected double _minScale;
        protected int _srid;

        protected XmlCommon _xmlCommon;

        protected MapSource(MapSourceTypes type)
        {
            Type = type;
            Init();
        }

        protected MapSource(string name, MapSourceTypes type, int srid)
        {
            Name = name;
            Type = type;
            Srid = srid;

            Init();
        }

        public CoordinationUnits CoordUnit
        {
            get { return _coordUnit; }
        }

        public string Copyright { get; set; }

        public string Description { get; set; }

        #region IMapSource Members

        public string Name { get; set; }

        public MapSourceTypes Type { get; protected set; }

        public int Srid
        {
            set
            {
                _srid = value;
                CoordinateSystem = SridParser.GetCoordinateSystemFromSrid(_srid);
                InchesPerUnit = SridParser.GetInchesPerUnit(_srid);
            }
            get { return _srid; }
        }

        public IPolygon MaxExtent { get; set; }

        public double MinScale
        {
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("Scale should be > 0.");
                if (value < _maxScale)
                    _minScale = value;
            }
            get { return _minScale; }
        }

        public double MaxScale
        {
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("Scale should be > 0.");
                if (value > _minScale)
                    _maxScale = value;
            }
            get { return _maxScale; }
        }

        public ICoordinateSystem CoordinateSystem { get; protected set; }

        public Uri SourceLogo { get; set; }

        public double InchesPerUnit { get; private set; }

        public bool Compare(MapSource other)
        {
            if (Name == other.Name &&
                Type == other.Type &&
                _srid == other._srid)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public virtual XElement ToXml()
        {
            return ToXml("MapSource");
        }

        public virtual void Parse(XElement mapSourceXml)
        {
            //_type = (MapSourceTypes)_xmlCommon.GetEnumElement(mapSourceXml, "MapSourceType", typeof(MapSourceTypes));
            Name = _xmlCommon.GetStringAttr(mapSourceXml, "Name");
            //_srid = _xmlCommon.GetIntElement(mapSourceXml, "Srid");
            Srid = _xmlCommon.GetIntAttr(mapSourceXml, "Srid");
            SourceLogo = _xmlCommon.GetUriElement(mapSourceXml, "SourceLogo");
            _maxScale = _xmlCommon.GetDoubleAttr(mapSourceXml, "MaxScale");
            _minScale = _xmlCommon.GetDoubleAttr(mapSourceXml, "MinScale");
        }

        #endregion

        private void Init()
        {
            _geoUtil = GeometryUtil.Default;
            MaxExtent = null;
            _minScale = AzukiMapSettings.DEFAULT_MINSCALE;
            _maxScale = AzukiMapSettings.DEFAULT_MAXSCALE;

            _xmlCommon = new XmlCommon();
        }

        public virtual XElement ToXml(string elementName)
        {
            /*
            <xs:attributeGroup name="MapSourceAttributes">
                <xs:attribute name="Name" type="xs:string" />
                <xs:attribute name="Srid" type="Srid" />
                <xs:attribute name="MaxScale" type="xs:double" />
                <xs:attribute name="MinScale" type="xs:double" />
                <xs:attribute name="CoordUnit" type="CoordinationUnit" />
            </xs:attributeGroup>
            <xs:group name="MapSourceElements">
                <xs:choice>
                  <xs:element name="Description" type="xs:string" />
                  <xs:element name="Copyright" type="xs:string" />
                  <xs:element name="MaxExtent">
                    <xs:complexType>
                      <xs:attributeGroup ref="BoundingBoxAttributes" />
                    </xs:complexType>
                  </xs:element>
                  <xs:element name="MapSourceLogo">
                    <xs:complexType>
                      <xs:all>
                        <xs:element name="Uri" type="Uri" />
                      </xs:all>
                    </xs:complexType>
                  </xs:element>
                </xs:choice>
             </xs:group>
             */
            var mapSourceXml = new XElement(elementName,
                                            _xmlCommon.CreateAttr("Name", Name),
                                            //_xmlCommon.CreateAttr("MapSourceType", _type),
                                            _xmlCommon.CreateAttr("Srid", _srid),
                                            _xmlCommon.CreateAttr("MaxScale", _maxScale),
                                            _xmlCommon.CreateAttr("MinScale", _minScale),
                                            _xmlCommon.CreateAttr("Description", Description),
                                            _xmlCommon.CreateAttr("Copyright", Copyright),
                                            _xmlCommon.GeometryToXml("MaxExtent", MaxExtent),
                                            _xmlCommon.CreateElement("SourceLogo", SourceLogo)
                //_xmlCommon.EnvelopeToXml("MaxExtent", _maxExtent)
                );
            return mapSourceXml;
        }
    }
}